﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using RFEngine.Audio.Internal;

namespace RFEngine.Audio
{
    [Serializable()]
    public sealed class Track : Sound
    {
        #region Fields

        private bool _UpdateNeeded;
        private bool _Destroyed;

        private float _PlaySpeed = 1.0f;
        private float _Volume = 1.0f;

        private Song _ParentSong;

        private ChorusEffect _ChorusEffect;
        private DistortionEffect _DistortionEffect;
        private EchoEffect _EchoEffect;
        private FlangeEffect _FlangeEffect;
        private HighpassEffect _HighPassEffect;
        private LowpassEffect _LowPassEffect;
        private NormalizeEffect _NormalizeEffect;
        private ReverbEffect _ReverbEffect;
        private PitchShiftEffect _PitchShiftEffect;

        #endregion

        #region Properties

        /// <summary>
        /// Gets the Current Position of this Track
        /// </summary>
        public int PlayPosition
        {
            get 
            {
                return (int)_Position; 
            }
            set
            {
                _Position = (uint)value;
                _UpdateNeeded = true;
            }
        }

        /// <summary>
        /// Gets the Legth of this Track.
        /// </summary>
        public int Length
        {
            get { return (int)_Length; }
        }

        /// <summary>
        /// Gets or Sets the level of volume this track plays at.
        /// </summary>
        public float Volume
        {
            get { return _Volume; }
            set
            {
                _Volume = value;
                _UpdateNeeded = true;
            }
        }

        /// <summary>
        /// Gets or Sets the speed at which this track plays.
        /// </summary>
        public float PlaySpeed
        {
            get { return _PlaySpeed; }
            set
            {
                _PlaySpeed = value;
                _UpdateNeeded = true;
            }
        }

        /// <summary>
        /// Gets or Sets the ChorusEffect for this track.
        /// </summary>
        public ChorusEffect ChorusEffect
        {
            get { return _ChorusEffect; }
            set
            {
                if (value != null)
                    _ChorusEffect = value;
            }
        }

        /// <summary>
        /// Gets or Sets the DistortionEffect for this track.
        /// </summary>
        public DistortionEffect DistortionEffect
        {
            get { return _DistortionEffect; }
            set
            {
                if (value != null)
                    _DistortionEffect = value;
            }
        }

        /// <summary>
        /// Gets or Sets the EchoEffect for this track.
        /// </summary>
        public EchoEffect EchoEffect
        {
            get { return _EchoEffect; }
            set
            {
                if (value != null)
                    _EchoEffect = value;
            }
        }

        /// <summary>
        /// Gets or Sets the FlangeEffect for this track.
        /// </summary>
        public FlangeEffect FlangeEffect
        {
            get { return _FlangeEffect; }
            set
            {
                if (value != null)
                    _FlangeEffect = value;
            }
        }

        /// <summary>
        /// Gets or Sets the HighPassEffect for this track.
        /// </summary>
        public HighpassEffect HighPassEffect
        {
            get { return _HighPassEffect; }
            set
            {
                if (value != null)
                    _HighPassEffect = value;
            }
        }

        /// <summary>
        /// Gets or Sets the LowPassEffect for this track.
        /// </summary>
        public LowpassEffect LowPassEffect
        {
            get { return _LowPassEffect; }
            set
            {
                if (value != null)
                    _LowPassEffect = value;
            }
        }

        /// <summary>
        /// Gets or Sets the NormalizeEffect for this track.
        /// </summary>
        public NormalizeEffect NormalizeEffect
        {
            get { return _NormalizeEffect; }
            set
            {
                if (value != null)
                    _NormalizeEffect = value;
            }
        }

        /// <summary>
        /// Gets or Sets the ReverbEffect for this track.
        /// </summary>
        public ReverbEffect ReverbEffect
        {
            get { return _ReverbEffect; }
            set
            {
                if (value != null)
                    _ReverbEffect = value;
            }
        }

        /// <summary>
        /// Gets or Sets the PitchShiftEffect for this track.
        /// </summary>
        public PitchShiftEffect PitchShiftEffect
        {
            get { return _PitchShiftEffect; }
            set
            {
                if (value != null)
                    _PitchShiftEffect = value;
            }
        }

        /// <summary>
        /// Gets the AudioState of this Track.
        /// </summary>
        public override AudioState AudioState
        {
            get { return base.AudioState; }
        }

        #endregion

        #region Methods

        #region Constructor(s)

        /// <summary>
        /// Constructs a new instance of this object.
        /// </summary>
        /// <param name="trackName">The name of this track</param>
        /// <param name="fileLocation">The file location to get the track data from.</param>
        internal Track(Song parent, string trackName, string fileLocation)
            : base(trackName, fileLocation) 
        {
            _ParentSong = parent;
            InitializeEffects();
        }

        /// <summary>
        /// Constructs a new instance of this object.
        /// </summary>
        /// <param name="trackName">The name of this track</param>
        /// <param name="trackData">The track data to used for sound.</param>
        internal Track(Song parent, string trackName, byte[] trackData)
            : base(trackName, trackData) 
        {
            _ParentSong = parent;
            InitializeEffects();
        }

        #endregion

        /// <summary>
        /// Method used for releasing this object from the manager.
        /// </summary>
        /// <param name="exitCode"></param>
        public void Destroy(int exitCode)
        {
            if (!_Destroyed)
            {                
                Destroy();
                _ParentSong.RemoveTrack(this);
            }
        }

        #region Private Methods

        private void InitializeEffects()
        {
            _ChorusEffect = new ChorusEffect(base._System);
            _DistortionEffect = new DistortionEffect(base._System);
            _EchoEffect = new EchoEffect(base._System);
            _FlangeEffect = new FlangeEffect(base._System);
            _HighPassEffect = new HighpassEffect(base._System);
            _LowPassEffect = new LowpassEffect(base._System);
            _NormalizeEffect = new NormalizeEffect(base._System);
            _ReverbEffect = new ReverbEffect(base._System);
            _PitchShiftEffect = new PitchShiftEffect(base._System);
        }

        #endregion

        #region Protected Methods

        protected override void Destroy()
        {
            if (!_Destroyed)
            {
                _ChorusEffect.Release();
                _DistortionEffect.Release();
                _EchoEffect.Release();
                _FlangeEffect.Release();
                _HighPassEffect.Release();
                _LowPassEffect.Release();
                _NormalizeEffect.Release();
                _ReverbEffect.Release();
                _PitchShiftEffect.Release();

                _Destroyed = true;
            }
            
            base.Destroy();
        }

        #endregion

        #region Internal Methods

        internal override void Update()
        {
            if (_Channel != null)
            {
                if (_UpdateNeeded)
                {
                    _Channel.setVolume(_BaseVolume * _Volume);
                    _Channel.setPosition(_Position, TIMEUNIT.MS);
                    _Channel.setFrequency(_BaseFrequency * _PlaySpeed);

                    _UpdateNeeded = false;

                    return;
                }

                _Channel.getVolume(ref _Volume);
                _Volume /= _BaseVolume;

                _Channel.getPosition(ref _Position, TIMEUNIT.MS);
                _Channel.getFrequency(ref _PlaySpeed);
                _PlaySpeed /= _BaseFrequency;
            }
        }

        #endregion

        #region Destructor

        /// <summary>
        /// Finalizer Called when the object is being Disposed.
        /// </summary>
        ~Track()
        {
            if (!_Destroyed)
                Destroy();
        }

        #endregion

        #endregion
    }
}
